<template>
  <el-sub-menu :index="props.index">
    <template #title>相机视角</template>
    <el-menu-item index="1-1" @click="cameraSetView">cameraSetView</el-menu-item>
    <el-menu-item index="1-2" @click="viewerFlyTo">viewerFlyTo</el-menu-item>
    <el-menu-item index="1-3" @click="cameraFlyTo">cameraFlyTo</el-menu-item>
    <el-menu-item index="1-4" @click="cameraLookAt">cameraLookAt</el-menu-item>
    <el-menu-item index="1-5" @click="centerPoint">centerPoint</el-menu-item>
    <el-menu-item index="1-6" @click="getCameraState">getCameraState</el-menu-item>
    <el-menu-item index="1-7" @click="cameraLookAtTransform">cameraLookAtTransform</el-menu-item>
  </el-sub-menu>
</template>

<script setup>
import * as Cesium from 'cesium'
import { useCesiumStore } from '@/stores/cesiumStore'

// 定义props
const props = defineProps({
  index: {
    type: String,
    required: true,
  },
})

// 使用 Cesium Store
const cesiumStore = useCesiumStore()
// setView 没有动画，适用于快速切换视角  (重庆渝中区)
const cameraSetView = () => {
  cesiumStore.viewerCesium.camera.setView({
    // 设定相机的目的地    // /fromDegrees 根据以度为单位给出的经度和纬度值返回 Cartesian3 位置
    destination: Cesium.Cartesian3.fromDegrees(
      106.62672254553621, // 经度
      29.572460283514193, // 纬度
      3073.8116032563867, // 高度（米）
    ),
    // 相机视口的方向  toRadians 将角度转换为弧度
    orientation: {
      heading: Cesium.Math.toRadians(258.5919406761868), //视口水平旋转Y0为正北方向      // 摇头，水平旋转，围绕Y轴，0为正北方向
      pitch: Cesium.Math.toRadians(-27.42679133546573), //视口上下旋转X -90为俯视地面    //点头，上下旋转，围绕X轴，-90为俯视地面
      roll: Cesium.Math.toRadians(0.00013239674423600495), //视口上下旋转Z 0为不翻转     // 歪头，视口的翻滚角度，围绕Z轴，0为不翻转
    },
  })
}

// viewerFlyTo 传递Cesium3DTileset 实例
const viewerFlyTo = async () => {
  // 创建3D Tiles图层  通过 Cesium Ion 资产 ID 创建一个 3D Tiles 数据集。
  // primitives.add() 方法的返回值是添加到集合中的对象本身，在这个例子中，它返回的就是传入的 Cesium3DTileset 实例
  const tileset = cesiumStore.viewerCesium.scene.primitives.add(
    //方法返回一个 Cesium3DTileset 实例
    await Cesium.Cesium3DTileset.fromIonAssetId(3432836),
  )
  cesiumStore.viewerCesium.flyTo(tileset)
}
//直接设置相机
const cameraFlyTo = () => {
  cesiumStore.viewerCesium.camera.flyTo({
    // 设定相机的目的地    // /fromDegrees 根据以度为单位给出的经度和纬度值返回 Cartesian3 位置 {x: -2850140.3007405344, y: 4655805.925395274, z: 3290571.0927250083}
    destination: new Cesium.Cartesian3(-2849788.917146671, 4655277.258728037, 3291198.164888067),
    // 相机视口的方向  toRadians 将角度转换为弧度
    orientation: {
      //姿态   Cesium.Math.toRadians 将角度转换为弧度
      heading: 2.098306124940061, // 摇头，水平旋转，围绕Y轴，0为正北方向
      pitch: -0.5743213591306051, // 点头，上下旋转，围绕X轴，-90为俯视地面
      roll: 0.00005483693127228406, // 歪头，视口的翻滚角度，围绕Z轴，0为不翻转
      // direction: direction,   (Cartesian3)
      // up: up,(Cartesian3)
    },
    //飞行完成时执行
    complete: () => {
      setTimeout(() => {
        cesiumStore.viewerCesium.camera.flyTo({
          // 设定相机的目的地    // /fromDegrees 根据以度为单位给出的经度和纬度值返回 Cartesian3 位置
          destination: Cesium.Cartesian3.fromDegrees(
            106.62672254553621, // 经度
            29.572460283514193, // 纬度
            3073.8116032563867, // 高度（米）
          ),
          // 相机视口的方向  toRadians 将角度转换为弧度
          orientation: {
            heading: Cesium.Math.toRadians(258.5919406761868), // 摇头，水平旋转，围绕Y轴，0为正北方向
            pitch: Cesium.Math.toRadians(-27.42679133546573), // 点头，上下旋转，围绕X轴，-90为俯视地面
            roll: Cesium.Math.toRadians(0.00013239674423600495), // 歪头，视口的翻滚角度，围绕Z轴，0为不翻转
          },
        })
      }, 3000)
    },
  })
}
//使用目标和偏移设置相机位置和方向   固定视角
//lookAt直接将视角跳转到目的地，旋转视角不会离开，用于锁定某个场景的视角 一个点
const cameraLookAt = () => {
  const heading = 2.2010704466764235
  const pitch = -0.4082165959392512
  const range = 2500 // 高度
  cesiumStore.viewerCesium.camera.lookAt(
    //使用目标和偏移设置相机位置和方向
    new Cesium.Cartesian3(-2849788.917146671, 4655277.258728037, 3291198.164888067), //世界坐标中的目标位置
    new Cesium.HeadingPitchRange(heading, pitch, range), //以目标为中心的本地东西向向上参考系中与目标的偏移量。
  ) //  设置相机方向和高度的方法
  // heading, // 水平角度(弧度)
  //   pitch,   // 俯仰角度(弧度)
  //   range    // 距离(米)
}

// lookAt的视角保持不变
// lookAtTransform的视角会随着参考系的旋转而旋转，相机围绕目标点转动
// lookAt会让相机始终从地理北方观察飞机
// lookAtTransform会让相机跟随飞机的朝向变化，始终从飞机的"前方"观察
//全局坐标系：固定的、统一的参考系统，用于描述整个世界中的绝对位置
// 局部坐标系：相对于特定物体或位置的坐标系，用于描述相对位置关系
const cameraLookAtTransform = () => {
  //设置以某个点作为相对坐标的中心点
  const center = Cesium.Cartesian3.fromDegrees(106.54121591146563, 29.557164483800573)
  //局部坐标系为:east-north-up坐标系，X:当地东向，Y:当地北向，Z:当地天顶方向
  //transform为局部坐标系到世界坐标系的齐次转换矩阵（包含旋转和平移）
  //从参考系（其东西向北向上的轴，以提供的原点为中心）计算 4x4 变换矩阵到提供的椭球体的固定参考系。
  const transform = Cesium.Transforms.eastNorthUpToFixedFrame(center) //它建立了一个以给定点为中心、方向为东-北-上的局部坐标系
  // 相机设置在局部坐标系的(-1200.0, -1200.0, 1200.0)处，相机的视线方向指向局部坐标系零点
  cesiumStore.viewerCesium.camera.lookAtTransform(
    transform, //局部参考系的中心点
    //  注意，由于此时视线方向与Z轴重合，所以程序内部将up方向设置为局部坐标系的Y方向，本例中也就是世界坐标系的Z方向。见下图示意。
    new Cesium.Cartesian3(1200, 1200, 1000),
  )
}

//从参考系计算四元数，其轴根据以提供原点为中心的航向-俯仰-滚动角度计算。航向是从局部东方向的旋转，其中正角度向东增加。Pitch 是从本地东西向北平面的旋转。正俯仰角位于平面上方。负俯仰角位于平面下方。Roll 是围绕本地东轴应用的第一个旋转。
//viewBoundingSphere 适合**“区域导向”**的视图控制，自动计算最佳视角以显示整个区域
const centerPoint = () => {
  // 参数1：视点的位置  new Cesium.BoundingSphere(position,20)
  // 参数2：相机的朝向  new Cesium.HeadingPitchRange(0,0,0)
  cesiumStore.viewerCesium.camera.viewBoundingSphere(
    //BoundingSphere 具有中心和半径的边界球体    边界球体的中心(Cartesian3)   边界球体的半径
    new Cesium.BoundingSphere(
      Cesium.Cartesian3.fromDegrees(
        106.62672254553621, // 经度
        29.572460283514193, // 纬度
        3073.8116032563867, // 高度（米）
      ),
      5000,
    ),
    // 定义局部帧中的航向角、俯仰角和范围  其中正角度向南增加。Pitch 是相对于局部 xy 平面的旋转。正俯仰角位于平面上方。负俯仰角位于平面下方。Range 是距帧中心的距离。 (弧度,弧度,米)
    new Cesium.HeadingPitchRange(0, -90, 0),
  )
}
 
const getCameraState = () => {
  const camera = cesiumStore.viewerCesium.camera
  // 获取位置和方向
  const position = camera.position
  const direction = camera.direction
  const up = camera.up

  // 获取姿态角  弧度
  const heading = camera.heading
  const pitch = camera.pitch
  const roll = camera.roll

  // 获取视野范围
  const fov = camera.frustum.fov

  console.log(
    '位置:',
    position,
    '方向:',
    direction,
    '相机的上方向向量:',
    up,
    '姿态:',
    heading,
    pitch,
    roll,
    '视野范围:',
    fov,
  )
}
</script>

<style lang="scss" scoped></style>
